package com.googlecode.jwsm;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.jar.*;

import javax.servlet.*;
import javax.servlet.http.*;

import org.jdom.*;
import org.jdom.output.*;

import com.googlecode.jwsm.security.SecurityManager;
import com.googlecode.jwsm.security.User;

import bsh.*;

/**
 * Servlet implementation class for Servlet: Deploy
 */
public class Deploy extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}
	
	protected synchronized void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		User user = SecurityManager.getSecurityFactory().login(request, response);
		if (user != null) {
			if (user.hasPrivilege("jwsm.service_deploy")) {
				Thread.currentThread().setName("Deploy");
				File directory = new File(Uploader.directory, request.getParameter("name"));
				String type = request.getParameter("serviceType");
				String[] visibleMethods = request.getParameterValues("visibleMethod");
				if ((type.equals("update")) || ((!directory.exists()) && (!directory.isDirectory()))) {
					HashMap outgoingXSLTMappings = new HashMap();
					HashMap incomingXSLTMappings = new HashMap();
					directory.mkdirs();
					
					// Stop the service
					if (type.equals("update")) {
						Service service = ServiceManager.getInstance().getService(request.getParameter("name"));
						service.stop();
					}
					
					// Move uploaded files to directory
					HashSet filesToKeep = new HashSet();
					Enumeration enumeration = request.getParameterNames();
					String key;
					int n;
					while (enumeration.hasMoreElements()) {
						key = (String)enumeration.nextElement();
						if (key.startsWith("fileName")) {
							try {
								n = Integer.parseInt(key.substring("fileName".length()));
								if (request.getParameter(key).endsWith(".bin")) {
									moveFile(new File(Uploader.directory, request.getParameter("fileName" + n)), new File(directory, request.getParameter("jar" + n)));
								}
								filesToKeep.add(request.getParameter("jar" + n));
							} catch(NumberFormatException exc) {}
						}
					}
					
					// Delete any files that are no longer used
					if (type.equals("update")) {
						File[] files = directory.listFiles(Service.jarFilter);
						for (int i = 0; i < files.length; i++) {
							if (!filesToKeep.contains(files[i].getName())) {
								Log.info("Deleting file: " + files[i].getName());
								if (!files[i].delete()) {
									files[i].deleteOnExit();
								}
							}
						}
					}
					
					// Create configuration XML
					try {
						Element root = new Element("configuration");
						Document document = new Document(root);
						
						Element child = new Element("main-class");
						child.setAttribute("defaultMethod", request.getParameter("defaultMethod"));
						if ("on".equals(request.getParameter("requestInstantiation"))) {
							child.setAttribute("instanceInstantiation", "true");
						} else {
							child.setAttribute("instanceInstantiation", "false");
						}
						if ("on".equals(request.getParameter("debugMode"))) {
							child.setAttribute("debug", "true");
						} else {
							child.setAttribute("debug", "false");
						}
						if ("on".equals(request.getParameter("interceptWSDL"))) {
							child.setAttribute("interceptWSDL", "true");
						} else {
							child.setAttribute("interceptWSDL", "false");
						}
						child.setText(request.getParameter("mainClass"));
						root.addContent(child);
						
						if (visibleMethods != null) {
							for (int i = 0; i < visibleMethods.length; i++) {
								child = new Element("visible-method");
								child.setText(visibleMethods[i]);
								String xsltAssociation = request.getParameter(visibleMethods[i] + "OutgoingXSLT");
								if ((xsltAssociation != null) && (!xsltAssociation.equals("<default>"))) {
									child.setAttribute("outgoingXSLT", xsltAssociation);
									outgoingXSLTMappings.put(visibleMethods[i], xsltAssociation);
								}
								xsltAssociation = request.getParameter(visibleMethods[i] + "IncomingXSLT");
								if ((xsltAssociation != null) && (!xsltAssociation.equals("<default>"))) {
									child.setAttribute("incomingXSLT", xsltAssociation);
									incomingXSLTMappings.put(visibleMethods[i], xsltAssociation);
								}
								root.addContent(child);
							}
						}
						
						if (request.getParameter("instantiation").trim().length() > 0) {
							child = new Element("instantiation");
							child.setText(request.getParameter("instantiation"));
							root.addContent(child);
						}
						
						XMLOutputter outputter = new XMLOutputter();
						FileOutputStream fos = new FileOutputStream(new File(directory, "configuration.xml"));
						outputter.output(document, fos);
						fos.flush();
						fos.close();
					} catch(Exception exc) {
						throw new ServletException(exc);
					}
					
					// Generate WSAR file
					File[] files = directory.listFiles();
					File jar = new File(Uploader.directory, request.getParameter("name") + ".wsar");
					JarOutputStream jos = new JarOutputStream(new FileOutputStream(jar));
					for (int i = 0; i < files.length; i++) {
						JarEntry entry = new JarEntry(files[i].getName());
						jos.putNextEntry(entry);
						FileInputStream fis = new FileInputStream(files[i]);
						int len;
						byte[] buf = new byte[512];
						while ((len = fis.read(buf)) != -1) {
							jos.write(buf, 0, len);
						}
						jos.flush();
						jos.closeEntry();
						fis.close();
					}
					jos.close();
					
					// Start the service
					boolean instanceInstantiation = false;
					if ((request.getParameter("requestInstantiation") != null) && (request.getParameter("requestInstantiation").trim().equals("on"))) {
						instanceInstantiation = true;
					}
					boolean debugMode = false;
					if ((request.getParameter("debugMode") != null) && (request.getParameter("debugMode").trim().equals("on"))) {
						debugMode = true;
					}
					boolean interceptWSDL = false;
					if ((request.getParameter("interceptWSDL") != null) && (request.getParameter("interceptWSDL").trim().equals("on"))) {
						interceptWSDL = true;
					}
					Service service = new Service(request.getParameter("name"), request.getParameter("mainClass"), request.getParameter("instantiation"), request.getParameter("defaultMethod"), visibleMethods, instanceInstantiation, debugMode, interceptWSDL);
					service.setOutgoingXSLTMappings(outgoingXSLTMappings);
					service.setIncomingXSLTMappings(incomingXSLTMappings);
					ServiceManager.getInstance().registerService(service);
					try {
						service.start();
					} catch (MalformedURLException e) {
						throw new ServletException(e);
					} catch (InstantiationException e) {
						throw new ServletException(e);
					} catch (IllegalAccessException e) {
						throw new ServletException(e);
					} catch (ClassNotFoundException e) {
						throw new ServletException(e);
					} catch (EvalError e) {
						throw new ServletException(e);
					}
					
					// Redirect to status page
					String message;
					if (type.equals("update")) {
						message = service.getName() + " was successfully updated";
					} else {
						message = service.getName() + " was successfully created";
					}
					response.sendRedirect("index.jsp?message=" + message);
				} else {
					response.sendRedirect("index.jsp?error=A service already exists by that name");
				}
			} else {
				response.sendRedirect("index.jsp?error=Access Denied attempting to deploy service");
			}
		} else {
			response.sendRedirect("index.jsp?error=Access Denied, you must first be logged in");
		}
	}
	
	public static final void moveFile(File src, File dest) throws IOException {
		FileInputStream fis = new FileInputStream(src);
		FileOutputStream fos = new FileOutputStream(dest);
		byte[] buf = new byte[512];
		int len;
		while ((len = fis.read(buf)) != -1) {
			fos.write(buf, 0, len);
		}
		fis.close();
		fos.flush();
		fos.close();
		if (!src.delete()) {
			src.deleteOnExit();
		}
	}

	public static void main(String[] args) throws Exception {
		File directory = new File("C:/wsm_deploy/runwaylighting");
		File[] files = directory.listFiles();
		File jar = new File("C:/wsm_deploy/test.zip");
		JarOutputStream jos = new JarOutputStream(new FileOutputStream(jar));
		
		for (int i = 0; i < files.length; i++) {
			JarEntry entry = new JarEntry(files[i].getName());
			jos.putNextEntry(entry);
			FileInputStream fis = new FileInputStream(files[i]);
			int len;
			byte[] buf = new byte[512];
			while ((len = fis.read(buf)) != -1) {
				jos.write(buf, 0, len);
			}
			jos.flush();
			jos.closeEntry();
			fis.close();
		}
		jos.close();
	}
}